﻿using System;
using System.IO;
using System.Windows.Forms;
using MEFAddin.Enums;
using MEFAddin.Interfaces;

namespace MEFAddin.Adapters
{
    public class LoggingAdapter : MEFAddin.Adapters.ILoggingAdapter
    {
        private IToolWindowContext _logWindow = null;

        private AddInContext _AddInContext;

        private IWindowAdapter _WindowAdapter;

        private string _logFileName;

        private dynamic _logWindowControl = null;

        private string _LogWindowName;

        public event AddInMessageEvent OnMessage;

        public event AddInMessageEvent OnWarning;

        public event AddInMessageEvent OnError;

        /// <summary>
        /// Initializes a new instance of the <see cref="LoggingAdapter"/> class.
        /// </summary>
        /// <param name="addInContext">The add in context.</param>
        /// <param name="windowAdapter">The window adapter.</param>
        /// <param name="logWindowName">Name of the log window.</param>
        public LoggingAdapter(AddInContext addInContext, IWindowAdapter windowAdapter, string logWindowName)
        {
            this._WindowAdapter = windowAdapter;
            this._AddInContext = addInContext;
            this._LogWindowName = logWindowName;
        }

        /// <summary>
        /// Shows the log window.
        /// </summary>
        public void ShowLogWindow()
        {
            _logWindow.Window.Visible = true;
        }

        /// <summary>
        /// Messages the type to string.
        /// </summary>
        /// <param name="msgType">Type of the MSG.</param>
        /// <returns></returns>
        public static string MessageTypeToString(MessageType msgType)
        {
            switch (msgType)
            {
                case MessageType.Message:
                    return "Message";
                case MessageType.Warning:
                    return "Warning";
                case MessageType.Error:
                    return "Error";
                default:
                    return "Unknown";
            }
        }

        /// <summary>
        /// Internals the log message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="messageType">Type of the message.</param>
        public void InternalLogMessage(string message, MessageType messageType)
        {
            this.LogMessageToFile(message, messageType);
            this.LogMessageToWindow(message, messageType);
        }

        /// <summary>
        /// Inits the log window.
        /// </summary>
        public void InitLogWindow()
        {
            try
            {
                if (this._logWindow == null)
                {
                    this._logWindow = this._WindowAdapter.FindOrCreateLogWindow(this._LogWindowName);
                    this._logWindowControl = ((dynamic)_logWindow.ControlObject);
                    string assemblyName = Path.GetFileName(System.Reflection.Assembly.GetExecutingAssembly().Location);
                    this.LogMessage(string.Format("Controller Loaded:{0} - {1}", this._AddInContext.WorkingDirectory, assemblyName));
                }
            }
            catch (Exception e)
            {
                this.LogError("Error InitLogWindow: " + e.ToString());
            }
        }

        /// <summary>
        /// Logs the warning.
        /// </summary>
        /// <param name="warning">The warning.</param>
        public void LogWarning(string warning)
        {
            if (this.OnWarning != null)
            {
                this.OnWarning(this, warning, MessageType.Message);
            }
            this.InternalLogMessage(warning, MessageType.Warning);
        }

        /// <summary>
        /// Logs the message.
        /// </summary>
        /// <param name="message">The message.</param>
        public void LogMessage(string message)
        {
            if (this.OnMessage != null)
            {
                this.OnMessage(this, message, MessageType.Message);
            }
            this.InternalLogMessage(message, MessageType.Message);
        }

        /// <summary>
        /// Logs the error.
        /// </summary>
        /// <param name="error">The error.</param>
        public void LogError(string error)
        {
            if (this.OnError != null)
            {
                this.OnError(this, error, MessageType.Message);
            }
            this.LogMessageToFile(error, MessageType.Error);
            if (this.LogMessageToWindow(error, MessageType.Error))
            {
                return;
            }
            MessageBox.Show(error);
        }

        /// <summary>
        /// Creates the log file.
        /// </summary>
        private void CreateLogFile()
        {
            try
            {
                this._logFileName = Path.Combine(_AddInContext.WorkingDirectory, "Addin.Log");
                this.LogMessage("Log File Created");
            }
            catch (Exception e)
            {
                this.LogError("Error CreateLogFile:" + e.ToString());
            }
        }

        /// <summary>
        /// Logs the message to window.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="messageType">Type of the message.</param>
        /// <returns></returns>
        private bool LogMessageToWindow(string message, MessageType messageType)
        {
            if (this._logWindowControl != null)
            {
                string msg = this.FormatMessage(message, messageType) + System.Environment.NewLine;
                this._logWindowControl.LogRawMessage(msg);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Logs the message to file.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="messageType">Type of the message.</param>
        private void LogMessageToFile(string message, MessageType messageType)
        {
            this.InitLogging();
            System.IO.StreamWriter sw = System.IO.File.AppendText(_logFileName);
            try
            {
                sw.WriteLine(FormatMessage(message, messageType));
            }
            finally
            {
                sw.Close();
            }
        }

        /// <summary>
        /// Inits the logging.
        /// </summary>
        private void InitLogging()
        {
            if (this._logFileName == null)
            {
                this.CreateLogFile();
            }
        }

        /// <summary>
        /// Formats the message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="messageType">Type of the message.</param>
        /// <returns></returns>
        private string FormatMessage(string message, MessageType messageType)
        {
            return string.Format("[{0:HH:MM:ss}][{1}]: {2}", DateTime.Now, MessageTypeToString(messageType), message);
        }
    }
}
